//package com.zdp.distributedemo.service;
//
//import com.zdp.distributedemo.mapper.OrderItemMapper;
//import com.zdp.distributedemo.mapper.OrderMapper;
//import com.zdp.distributedemo.mapper.ProductMapper;
//import com.zdp.distributedemo.model.Order;
//import com.zdp.distributedemo.model.OrderItem;
//import com.zdp.distributedemo.model.Product;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.PlatformTransactionManager;
//import org.springframework.transaction.TransactionDefinition;
//import org.springframework.transaction.TransactionStatus;
//
//import javax.annotation.Resource;
//import java.math.BigDecimal;
//import java.util.Date;
//
///**
// * @author sesshomaru
// * @date 2020/10/9 22:54
// *
// * 1.通过update行锁来控制，把扣减库存的操作拿到数据库中操作而不再在程序中完成
// *
// * 解决思路1:
// *          在 校验库存 和 扣减库存统一加锁, 使之成为一个原子性的操作,这时只有获得了锁的线程才可以检验并且扣减库存
// * 方案1:
// *       加同步锁(分布式环境没用)
// *       现象:
// *          出现超卖
// *          加了锁仍然会出现部分超卖，这是因为方法上加了事务@Transactional，线程1的事务1更新了数据还未提交到数据库中，线程2就进来
// *          发现库存还是1就又扣减了一次库存，此时库存就被扣减了2次出现了超卖
// *       解决方法:
// *          改用手动事务就是线程先拿到锁然后在执行手动的事务，这样就保障及保障了线程的顺序执行也避免了事务提交速度慢于线程获取锁的速度
// *          导致的后一个线程获取到错误的库存数而引发的超卖
// *          简单来说就是事务的开启和提交都是在获得锁和释放锁中间的
// *       流程:
// *          获取锁 ---> 开启事务 ---> 执行业务方法 ---> 提交事务 ---> 释放锁
// */
//@Service
//@Slf4j
//public class 同步锁方式 {
//
//    @Resource
//    private OrderMapper orderMapper;
//    @Resource
//    private OrderItemMapper orderItemMapper;
//    @Resource
//    private ProductMapper productMapper;
//    //购买商品id
//    private int purchaseProductId = 100100;
//    //购买商品数量
//    private int purchaseProductNum = 1;
//    // 手动控制事务
//    @Autowired
//    private PlatformTransactionManager platformTransactionManager;
//    @Autowired
//    private TransactionDefinition transactionDefinition;
//
//    // @Transactional(rollbackFor = Exception.class)
//    public synchronized Integer createOrder() throws Exception{
//
//        // 进入方法是首先获取事务
//        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
//
//        Product product = productMapper.selectByPrimaryKey(purchaseProductId);
//        if (product==null){
//            // 异常时事务回滚
//            platformTransactionManager.rollback(transactionStatus);
//            throw new Exception("购买商品："+purchaseProductId+"不存在");
//        }
//        //商品当前库存
//        Integer currentCount = product.getCount();
//        log.info("当前线程:{},库存数:{}", Thread.currentThread().getName(), currentCount);
//
//        //校验库存
//        if (purchaseProductNum > currentCount){
//            // 异常时事务回滚
//            platformTransactionManager.rollback(transactionStatus);
//            throw new Exception("商品"+purchaseProductId+"仅剩"+currentCount+"件，无法购买");
//        }
//       /*
//       现象:
//            出现超卖。原因是5个线程同时都拿到的库存是1而且都可以通过判断进入下单逻辑
//       优化:
//            不在程序中进行扣减库存采用update的行锁来控制库存
//            行锁:两个数据库的更新sql是有执行的先后顺序的
//       原有代码:
//       //计算剩余库存
//        Integer leftCount = currentCount - purchaseProductNum;
//        //更新库存
//        product.setCount(leftCount);
//        product.setUpdateTime(new Date());
//        productMapper.updateByPrimaryKeySelective(product);*/
//
//        productMapper.updateProductCount(purchaseProductNum, new Date(), product.getId());
//        // 检索商品的库存
//        // 商品库存为负数抛出异常使异常的下单数据回滚
//
//        Order order = new Order();
//        order.setOrderAmount(product.getPrice().multiply(new BigDecimal(purchaseProductNum)));
//        order.setOrderStatus(1);//待处理
//        order.setReceiverName("xxx");
//        order.setReceiverMobile("13311112222");
//        order.setCreateTime(new Date());
//        order.setCreateUser("xxx");
//        order.setUpdateTime(new Date());
//        order.setUpdateUser("xxx");
//        orderMapper.insertSelective(order);
//
//        OrderItem orderItem = new OrderItem();
//        orderItem.setOrderId(order.getId());
//        orderItem.setProductId(product.getId());
//        orderItem.setPurchasePrice(product.getPrice());
//        orderItem.setPurchaseNum(purchaseProductNum);
//        orderItem.setCreateTime(new Date());
//        orderItem.setUpdateTime(new Date());
//        orderItemMapper.insertSelective(orderItem);
//
//        // 方法最后手动的提交事务
//        platformTransactionManager.commit(transactionStatus);
//
//        return order.getId();
//    }
//}
